/**
 * mappanel 模块, 提供地图上的各种东西. 其中的核心是MapPanel.map .
 */

var FG;
if (!FG)
    FG = {};

FG.MAP_BASELAYERS = {
    opencycle: L.tileLayer.provider("Thunderforest.Landscape"),
    osm: L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar'}),
    gaodeNormal: L.tileLayer.chinaProvider("GaoDe.Normal.Map", {maxZoom:18,minZoom:4}),
    gaodeSatImg: L.tileLayer.chinaProvider("GaoDe.Satellite.Map", {maxZoom:18,minZoom:4}),
    gaodeSatAnn: L.tileLayer.chinaProvider("GaoDe.Satellite.Annotion", {maxZoom:18,minZoom:4}),
    mapabc: L.tileLayer.chinaProvider("MapABC.Normal.Map", {maxZoom:18,minZoom:4}),
    tdtNormalImg: L.tileLayer.chinaProvider("TianDiTu.Normal.Map", {maxZoom:18,minZoom:4}),
    tdtNormalAnn: L.tileLayer.chinaProvider("TianDiTu.Normal.Annotion", {maxZoom:18,minZoom:4}),
    tdtSatImg: L.tileLayer.chinaProvider("TianDiTu.Satellite.Map", {maxZoom:18,minZoom:4}),
    tdtSatAnn: L.tileLayer.chinaProvider("TianDiTu.Satellite.Annotion", {maxZoom:18,minZoom:4}),
    tdtTerImg: L.tileLayer.chinaProvider("TianDiTu.Terrain.Map", {maxZoom:18,minZoom:4}),
    tdtTerAnn: L.tileLayer.chinaProvider("TianDiTu.Terrain.Annotion", {maxZoom:18,minZoom:4})
};

FG.MAP_DEFAULT_LAYERS = [
    {
        name:"天地图",
        sublayers: ["tdtSatImg", "tdtSatAnn"]
    },
    {
        name:"地形图",
        sublayers: ["opencycle"]
    },
    {
        name:"高德地图",
        sublayers: ["gaodeSatImg", "gaodeSatAnn"]
    }
];

L.drawLocal.draw.handlers.marker.tooltip.start = '标定一个坐标点';
L.drawLocal.draw.handlers.rectangle.tooltip.start = '画一个矩形区域';
L.drawLocal.draw.handlers.polygon.tooltip.start = '画一个多边形区域';
L.drawLocal.draw.handlers.polygon.tooltip.cont = '点击下一个点';
L.drawLocal.draw.handlers.polygon.tooltip.end = '点击起始点或双击可完成绘制';
L.drawLocal.draw.handlers.simpleshape.tooltip.end = '放开鼠标，完成绘制';

/**
 * 控制器列表, 尚未用到
 */
FG.MAP_DEFAULT_CONTROLS = {};

FG.MAP_DEFAULT_VIEW = {center: [38, 100.5], zoom: 5};

FG.MAP_OPTS = {
    attributionControl: false,
    contextmenu: true,
    contextmenuWidth: 200,
    contextmenuAnchor: [5, 5],
    contextmenuItems: [{
        separator: true
    }, {
        text: "添加坐标点",
        iconCls: "fa fa-map-marker",
        callback: function(opts) {
            var info = {
                type: 'Feature',
                geometry: {
                    type: "Point",
                    coordinates: [opts.latlng.lng, opts.latlng.lat]
                }
            };
            DX.shout('feature:drawn', info);
        }
    }, {
        text: "勾选矩形区域",
        iconCls: "fa fa-square",
        callback: function(opts) {
            DX.shout("start:draw:rect!");
        }
    }, {
        text: "勾选多边形区域",
        iconCls: "fa fa-bookmark fa-rotate-270",
        callback: function(opts) {
            DX.shout("start:draw:polygon!")
        }
    }]
};

FG.RIGHTBAR_WIDTH = 300;
FG.RIGHTBAR_TOP = 120;
FG.RIGHTBAR_BOTTOM = 120;

FG.MapPanel = function(options){
    /**
     * this.map, etc.
     */

    var this_ = this;
    this.moduleInfo = {
        name: 'mapPanel',
        zhName: '地图面板',
        desc: '',
        exportList: [
            'registerFeatureClass',
            'registerWidgetClass',
            'registerFeatureModelParser',
            'registerDBFeatureOptsParser',
            'parseFeatureModel',
            'createFeature',
            'createWidget',
            'pushFeatureGroup'
        ]
    };

    this.options = _.extend({
        layers: FG.MAP_DEFAULT_LAYERS,
        controls: FG.MAP_DEFAULT_CONTROLS,
        view: FG.MAP_DEFAULT_VIEW
    }, options || {});

    if (_.has(this.options, 'app')) {
        this.app = this.options.app;
    }
    
    var target = 'map_panel';
    if (_.has(this.options, 'target')) {
        this.$target = $('#'+this.options.target);
        target = this.options.target;
    } else if (_.has(this.options, 'pager')) {
         // 有pager时可自行添加图层
         this.$target = this.options.pager.addLayer('mapPanel', '<div id="' + target + '"></div>')
    }
    
    this.$target.addClass("sidebar-map");
    this.map = L.map(target, FG.MAP_OPTS);
    this.map.setView(this.options.view.center, this.options.view.zoom);
    
    this.featureClasses = {};
    this.widgetClasses = {};
    this.featureModelParsers = [];
    this.dbFeatureOptsParsers = [];
    
    // 图层
    this.basemaps = {};
    _.forEach(this.options.layers, function (info) {
        var sublayers = _.map(info.sublayers, function(name){return FG.MAP_BASELAYERS[name]});
        this_.basemaps[info.name] = L.layerGroup(sublayers);
    });

    this.basemaps[this.options.layers[0].name].addTo(this.map);

    this.featureGroupViews = {};
    _.each(['pitem', 'vmap', 'tmp'], function(name) {
        this_.pushFeatureGroup(name);
    });
    
    var overlays = {
        "矢量地图": this.featureGroupViews.vmap.featureGroup,
        "工程图层": this.featureGroupViews.pitem.featureGroup
    };

    // 绘图插件
    this.drawers = {
        rect: new L.Draw.Rectangle(this.map),
        point: new L.Draw.Marker(this.map),
        line: new L.Draw.Polyline(this.map),
        polygon: new L.Draw.Polygon(this.map)
    };
    
    this.attrControl = L.control.attribution({});
    this.attrControl.addTo(this.map);

    // 图层控制器
    this.layerControl = L.control.layers(this.basemaps, overlays, {
        position: 'bottomright'
    });
    this.layerControl.addTo(this.map);

    var mapSize = this.map.getSize();
    this.rightbar = L.control.dialog({
        size: [FG.RIGHTBAR_WIDTH, mapSize.y-FG.RIGHTBAR_TOP-FG.RIGHTBAR_BOTTOM],
        minSize: [FG.RIGHTBAR_WIDTH, 100],
        maxSize: [FG.RIGHTBAR_WIDTH, 9000],
        anchor: [FG.RIGHTBAR_TOP, -FG.RIGHTBAR_WIDTH-10],
        position:'topright',
        initOpen: false
    }).addTo(this.map);
    this.rightbar.lock();
    this.rightbar.setContent('<div id="rightbar"></div>');
    this.rightbar.close();
    // this.rightbar.setLocation([300, -350]);
    // this.rightbar.open();
    


    // display lonlat
    this.map.coordinatesControl = L.control.coordinates({
        position:"bottomleft", //optional default "bootomright"
        decimals:5, //optional default 4
        decimalSeperator:".", //optional default "."
        labelTemplateLat:"{y}", //optional default "Lat: {y}"
        labelTemplateLng:"{x}", //optional default "Lng: {x}"
        enableUserInput:false, //optional default true
        useDMS:(DX.get('mapCoordinateType') !== 'degree'), //optional default false
        useLatLngOrder: true, //ordering of labels, default false-> lng-lat
        //markerType: L.marker, //optional default L.marker
        //markerProps: {} //optional default {}
        labelFormatterLng: function(lng) {
            var rawLabel = this_.map.coordinatesControl._getNumber(lng, this_.map.coordinatesControl.options);
            if (lng >= 0) {
                return rawLabel + 'E'
            } else {
                return rawLabel.slice(1) + 'W'
            }
        },
        labelFormatterLat: function(lat) {
            var rawLabel = this_.map.coordinatesControl._getNumber(lat, this_.map.coordinatesControl.options);
            if (lat >= 0) {
                return rawLabel + 'N'
            } else {
                return rawLabel.slice(1) + 'S'
            }
        }
    }).addTo(this.map);
    
    L.DomEvent.addListener(this.map.coordinatesControl._container, "click", function(e) {
        e.stopPropagation();
        if (DX.get('mapCoordinateType') === 'degree') {
            DX.set('mapCoordinateType', 'dms')
        } else {
            DX.set('mapCoordinateType', 'degree')
        }
        this_.map.coordinatesControl.options.useDMS = (DX.get('mapCoordinateType') !== 'degree')
        this_.map.fire('mousemove', {latlng: this_.map.mouseEventToLatLng(e)});
    });

    // 比例尺
    L.control.scale({imperial: false}).addTo(this.map);

    this.connectSignals();
};


// 地图操作

FG.MapPanel.prototype.hide = function() {
    this.$target.hide();
};

FG.MapPanel.prototype.show = function() {
    this.$target.show();
};

FG.MapPanel.prototype.goTo = function(location, zoom) {
    try { // 假定location为Feature对象或其uuid.
        var feature, featureView;
        if (_.isString(location)) {
            for (gname in this.featureGroupViews) {
                featureView = this.featureGroupViews[gname].getByTag(location);
                if (!!featureView) {
                    feature = featureView.feature;
                    break;
                }
            }
            if (!feature) {
                return;
            }
        } else {
            feature = location;
        }
        try {
            var bounds = feature.getBounds();
            this.map.fitBounds(bounds, {
                padding: [300, 50]
            });
        } catch (e) {
            if (!feature.getPopup()) {
                this.map.setView(feature.getLatLng());
            }
        }
        if (!!zoom) {
            this.map.setZoom(zoom);
        }
    } catch (e) {
        // location为[lat, lng]数组或Leaflet的LatLng对象.
        this.map.setView(location, zoom, {animate: true});
    }
};

FG.MapPanel.prototype.getLayers = function() {
    // TODO: return layerNames
};

FG.MapPanel.prototype.getCurrentLayer = function() {
    // TODO: return currentLayerName
};

FG.MapPanel.prototype.switchLayer = function(layerName) {
    // TODO
};

// Feature相关

FG.MapPanel.prototype.parseFeatureModel = function(model) {
    for (var i=0; i<this.featureModelParsers.length; i+=1) {
        var res = this.featureModelParsers[i].parser(model);
        if (!res) {
            continue;
        } else {
            return res;
        }
    }
};

FG.MapPanel.prototype.createFeature = function(featureClass, latlngs, featureOpts) {
    if (_.isString(featureClass)) {
        featureClass = this.featureClasses[featureClass];
    }
    var feature = new featureClass(latlngs, featureOpts);
    return feature;
};

FG.MapPanel.prototype.createWidget = function(widgetClass, widgetOpts, source) {
    if (_.isString(widgetClass)) {
        widgetClass = this.widgetClasses[widgetClass];
    }
    widgetOpts = _.extend({}, widgetOpts);
    var widget = new widgetClass(widgetOpts, source);
    return widget;
};

FG.MapPanel.prototype.registerFeatureClass = function(featureClass) {
    this.featureClasses[featureClass.className] = featureClass;
};

FG.MapPanel.prototype.registerWidgetClass = function(widgetClass) {
    this.widgetClasses[widgetClass.className] = widgetClass;
};

FG.MapPanel.prototype.registerFeatureModelParser = function(modelParser, priority) {
    var rec = {
        parser: modelParser,
        priority: priority
    };
    var i = _.sortedIndex(this.featureModelParsers, rec, 'priority');
    this.featureModelParsers.splice(i, 0, rec);
};

FG.MapPanel.prototype.registerDBFeatureOptsParser = function(parser, priority) {
    var rec = {
        parser: parser,
        priority: priority
    };
    var i = _.sortedIndex(this.dbFeatureOptsParsers, rec, 'priority');
    this.dbFeatureOptsParsers.splice(i, 0, rec);
};

FG.MapPanel.prototype.pushDBFeature = function(opts) {
    var this_ = this;
    var dbFeatureOpts;
    for (var i=0; i<this.dbFeatureOptsParsers.length; i+=1) {
        dbFeatureOpts = this.dbFeatureOptsParsers[i].parser(opts);
        if (!!dbFeatureOpts) {
            DX.once('feature:data:rendered', _.debounce(function(featureView) {
                featureView.setFocus(true);
                if (!!opts.focus) {
                    this_.goTo(featureView.feature);
                }
            }, 50));
            DX.shout('dbfeature:push!', dbFeatureOpts);
            return;
        }
    }
};

FG.MapPanel.prototype.pushFeatureGroup = function(groupName) {
    if (!_.has(this.featureGroupViews, groupName)) {
        var fgView = new FG.LBFeatureGroupView(),
            fg = fgView.featureGroup;
        
        fgView.addOnMap(this.map);
        fg.isOnMap = true;
        
        this.featureGroupViews[groupName] = fgView;
    }
};

FG.MapPanel.prototype.getFeatureGroups = function() {
    return _.keys(this.featureGroupViews);
};

FG.MapPanel.prototype.getFeatureGroupView = function(groupName) {
    return this.featureGroupViews[groupName];
};

FG.MapPanel.prototype.getFeatureGroup = function(groupName) {
    var featureGroupView = this.getFeatureGroupView(groupName);
    if (!featureGroupView) {
        return null
    }
    return featureGroupView.featureGroup;
};

FG.MapPanel.prototype.showFeatureGroup = function(groupName) {
    var fg = this.getFeatureGroup(groupName);
    if (!!fg.isOnMap) {
        return;
    }
    if (!!fg) {
        this.map.addLayer(fg);
        fg.isOnMap = true;
    }
};

FG.MapPanel.prototype.hideFeatureGroup = function(groupName) {
    var fg = this.getFeatureGroup(groupName);
    if (!fg.isOnMap) {
        return;
    }
    if (!!fg) {
        this.map.removeLayer(fg);
        fg.isOnMap = false;
    }
};

FG.MapPanel.prototype.clearFeatures = function(groupName) {
    if (!groupName) {
        _.each(this.featureGroupViews, function(fgv) {
            fgv.clearAll();
        })
    } else {
        var featureGroupView = this.getFeatureGroupView(groupName);
        if (!!featureGroupView) {
            featureGroupView.clearAll();
        }
    }
};

FG.MapPanel.prototype.pushFeature = function(groupName, feature) {
    var featureGroupView = this.getFeatureGroupView(groupName);
    if (!!featureGroupView) {
        featureGroupView.pushEntry(feature);
    }
};

FG.MapPanel.prototype.delFeature = function(groupName, feature) {
    var featureGroupView = this.getFeatureGroupView(groupName);
    if (!!featureGroupView) {
        featureGroupView.deleteEntry(feature);
    }
};

FG.MapPanel.prototype.showTmpMarker = function(latlng) {
    this.featureGroupViews.tmp.featureGroup.addLayer(L.marker(latlng, {
        clickable: false,
        opacity: 0.6
    }));
};

FG.MapPanel.prototype.hideTmpMarker = function() {
    this.featureGroupViews.tmp.clearAll();
};

// 绘图插件相关

FG.MapPanel.prototype.getDrawTypes = function() {
    return _.keys(this.drawers);
};

FG.MapPanel.prototype.startDraw = function(drawType) {
    this.drawers[drawType].enable();
};

FG.MapPanel.prototype.stopDraw = function(drawType) {
    this.drawers[drawType].disable();
};

// RightBar
FG.MapPanel.prototype.openRightbar = function() { this.rightbar.open(); };
FG.MapPanel.prototype.closeRightbar = function() { this.rightbar.close(); };
FG.MapPanel.prototype.setRightbarContent = function(content) {
    if (!content) { content = '' }
    var wrapped_content = '<div id="rightbar">' + content + '</div>';
    this.rightbar.setContent(wrapped_content);
};
FG.MapPanel.prototype.clearRightbarContent = function() {
    this.rightbar.setContent('<div id="rightbar"></div>');
};

// 坐标拷贝

FG.MapPanel.prototype.copyCoordinates = function(e) {
    // context: map
    var label = this.coordinatesControl._createCoordinateLabel(e.latlng);
    EX.copyTextToClipboard(label);
    DX.log('已拷贝: ' + label);
};

//
// FG.SEL_REGION_TYPE =
//     '<div class="" style="height: 200px; background-color: lightgray;">' +
//     '</div>';

// FG.MapPanel.prototype.selItemType = function(opts) {
//     var uuid = DX.gen_uuid12();
//     if (opts.drawType === 'polygon') {
//         layer.open({
//             type: 1,
//             shade: false,
//             title: '测试选择',
//             content: $('#region_select')
//         });
//         //alertify.confirm(FG.SEL_REGION_TYPE, function(e) {
//         //    if (e) {
//         //        DX.shout('polygon:add!', _.extend({uuid:uuid},  opts));
//         //    }
//         //})
//     }
// };



FG.MapPanel.prototype.connectSignals = function() {
    var this_ = this;

    //////// 已整理的部分 ////////////

    // 地图相关
    DX.on('show:mappanel!', function() { this_.show(); });
    DX.on('hide:mappanel!', function() { this_.hide(); });
    DX.on('map:goto!', function(location, zoom) { this_.goTo(location, zoom); });

    DX.on('rightbar:open!', function() {this_.openRightbar()});
    DX.on('rightbar:close!', function() {this_.closeRightbar()});
    DX.on('rightbar:content:set!', function(content) {this_.setRightbarContent(content)});
    DX.on('rightbar:content:clear!', function() {this_.clearRightbarContent()});
    
    // 行为
    DX.on('map:feature:add!', function(groupName, feature) { this_.pushFeature(groupName, feature) });
    DX.on('map:feature:update!', function(groupName, feature) { this_.pushFeature(groupName, feature) });
    DX.on('map:feature:push!', function(groupName, feature) { this_.pushFeature(groupName, feature) });
    DX.on('map:feature:del!', function(groupName, feature) { this_.delFeature(groupName, feature) });

    DX.on('map:feature:group:push!', function(groupName) { this_.pushFeatureGroup(groupName) });
    DX.on('map:feature:group:show!', function(groupName) { this_.showFeatureGroup(groupName) });
    DX.on('map:feature:group:hide!', function(groupName) { this_.hideFeatureGroup(groupName) });
    
    // 绘图插件相关
    DX.on('start:draw:rect!', function(){
        this_.startDraw('rect');
    });
    DX.on('start:draw:point!', function(){
        this_.startDraw('point');
    });
    DX.on('start:draw:line!', function(){
        this_.startDraw('line');
    });
    DX.on('start:draw:polygon!', function(){
        this_.startDraw('polygon');
    });
    DX.on('stop:draw:rect!', function(){
        this_.stopDraw('rect');
    });
    DX.on('stop:draw:point!', function(){
        this_.stopDraw('point');
    });
    DX.on('stop:draw:line!', function(){
        this_.stopDraw('line');
    });
    DX.on('stop:draw:polygon!', function(){
        this_.stopDraw('polygon');
    });

    // 绘图的响应.
    this.map.on('draw:created', function (e) {
        // 这里的layer是指画出来的物体, 如点或区域等.
        var type = e.layerType,
            layer = e.layer,
            featureType, info;

        DX.shout('draw:end');

        if (type === 'marker') {
            var latlng = layer.getLatLng();
            info = {
                type: 'Feature',
                geometry: {
                    type: "Point",
                    coordinates: [latlng.lng, latlng.lat]
                }
            };
            this_.stopDraw('point');
        } else if (type === 'rectangle') {
            var bounds = layer.getBounds();
            var lon1 = bounds.getWest(),
                lon2 = bounds.getEast(),
                lat1 = bounds.getSouth(),
                lat2 = bounds.getNorth(),
                center = bounds.getCenter();
            info = {
                type: 'Rect',
                bounds: {
                    lon1: lon1, lon2: lon2, lat1: lat1, lat2:lat2
                }
            };
            this_.stopDraw('rect');
        } else if (type === 'polyline') {
            var lonlats = _.map(layer.getLatLngs(), function(ll) {
                return [ll.lng, ll.lat]
            });
            info = {
                type: 'Feature',
                geometry: {
                    type: 'LineString',
                    coordinates: lonlats
                }
            };
            this_.stopDraw('line');
        } else if (type === 'polygon') {
            var lonlats = _.map(layer.getLatLngs(), function(ll) {
                return [ll.lng, ll.lat]
            });
            lonlats.push(lonlats[0]);
            info = {
                type: 'Feature',
                geometry: {
                    type: 'Polygon',
                    coordinates: [lonlats]
                }
            };
            this_.stopDraw('polygon');
        }
        
        DX.shout('feature:drawn', info);
    });

    // 右键菜单
    this.map.on('contextmenu.show', function(opts) {
        var cmenu = opts.contextmenu,
            target = opts.relatedTarget,
            latlng = cmenu._showLocation.latlng;
        label = this.coordinatesControl._createCoordinateLabel(latlng);

        cmenu.insertItem({
            text: '<div title="点击可拷贝">' + label + '</div>',
            callback: this_.copyCoordinates,
            hideOnSelect: false
        }, 0);

        if (!target) {
            this_.showTmpMarker(latlng);
        }
    });

    this.map.on('contextmenu.hide', function(opts) {
        var cmenu = opts.contextmenu;
        cmenu.removeItem(0);
        this_.hideTmpMarker();
    });

    this.map.on('resize', function(e) {
        this_.rightbar.setSize([FG.RIGHTBAR_WIDTH, e.newSize.y - FG.RIGHTBAR_TOP - FG.RIGHTBAR_BOTTOM]);
    });
};

